# import warnings
# warnings.filterwarnings('ignore')
import os
# os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
# tf.compat.v1.logging.set_verbosity(40)
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras import utils, models, optimizers, losses, metrics, Input, Model
from tensorflow.keras.layers import Dense, Activation, Conv2D, MaxPooling2D, Flatten, Dropout, ReLU, BatchNormalization

tf.random.set_seed(777)
np.random.seed(777)

(x_train,y_train),(x_test,y_test)=tf.keras.datasets.cifar10.load_data()

idx = np.random.permutation(len(x_train))
x_train = x_train[idx]
y_train = y_train[idx]

x_train=x_train.reshape([-1,32,32,3]).astype('float32') / 255
x_test=x_test.reshape([-1,32,32,3]).astype('float32') / 255

print('x_train:', x_train.shape)
print('y_train:', y_train.shape)
print('x_test:', x_test.shape)
print('y_test:', y_test.shape)

def ConvBnRelu(x, out_ch):
    x = Conv2D(out_ch, (3, 3), padding='same')(x)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    return x


def MyMaxPooling(x):
    return MaxPooling2D([2, 2], [2, 2], padding='same')(x)


inputs = Input([32, 32, 3])
x = ConvBnRelu(inputs, 64)
x = ConvBnRelu(x, 64)
x = MyMaxPooling(x)

x = ConvBnRelu(x, 128)
x = ConvBnRelu(x, 128)
x = MyMaxPooling(x)

x = ConvBnRelu(x, 256)
x = ConvBnRelu(x, 256)
x = ConvBnRelu(x, 256)
x = MyMaxPooling(x)

x = ConvBnRelu(x, 512)
x = ConvBnRelu(x, 512)
x = ConvBnRelu(x, 512)
x = MyMaxPooling(x)

x = ConvBnRelu(x, 512)
x = ConvBnRelu(x, 512)
x = ConvBnRelu(x, 512)
x = MyMaxPooling(x)

x = Flatten()(x)
x = Dense(256, activation='relu')(x)
x = Dense(64, activation='relu')(x)
x = Dense(10, activation='softmax')(x)

model = Model(inputs, x)
model.summary()

model.compile(loss=losses.SparseCategoricalCrossentropy(),
              optimizer=optimizers.Adam(lr=0.001),
              metrics=['accuracy'])

history=model.fit(x_train, y_train, batch_size=64, epochs=3, validation_split=0.1)

score=model.evaluate(x_test, y_test)
print('accuracy',score[1])
print('loss',score[0])
